---
description: Digital GPIO
title: Digital IO (GPIO)
sidebar_position: 49
---

# Digital IO (GPIO)

DeviceScript provides access to digital GPIO (General Purpose Input/Output) operations
on pins that do **not** require precise real time timings.

It is recommended to encapsulate the GPIO access into server implementation as they are rather low level.

:::caution

If your application needs consistent response times of under 10ms, you can either implement the driver
natively in C using interrupts, or better yet offload it to an [external Jacdac module](/developer/drivers#jacdac-modules).

:::


## Pin mappings

While you can use hardware GPIO numbers with the `ds.gpio()` function,
it is highly recommended that you instead import a board definition file an use pin names
matching silk on the hardware.

```ts
import { pins } from "@dsboard/adafruit_qt_py_c3"

// highlight-next-line
const A2 = pins.A2_D2
```

The doc-string for `pins.A2_D2` will tell you GPIO number (`1` in this case).
Using named pins is also less error-prone since pins used for internal
functions are not exposed through the `pins` object and the pins that are
exposed are annotated with type (input, output, analog, etc.) which is then
required by the `startSomething()` functions.

Pins generally share names for boards with the same pinout.
In particular, QT Py and XIAO share names.

The `gpio()` function does not check for pin functions or usage.
It will return `undefined` when named pin is not available or used for something else.

```ts
import { gpio } from "@devicescript/core"

// highlight-next-line
const P0 = gpio(0)
```

## Mode

The pin can be access through the generic `gpio` function or through board specific packages
that provide predefined pin mappings (see [devices](/devices)).

You can configure the input/output mode through `setMode`.

```ts
import { gpio, GPIOMode } from "@devicescript/core"
import "@devicescript/gpio"

// p0 -> output
const p0 = gpio(0)
// highlight-next-line
await p0.setMode(GPIOMode.Output)

// P1 -> input
const p1 = gpio(1)
// highlight-next-line
await p1.setMode(GPIOMode.Input)
```

## Output

Use `write` to set the output value of a pin. This example flips a pin state every second.

```ts
import { gpio, GPIOMode } from "@devicescript/core"
import "@devicescript/gpio"

const p0 = gpio(0)
await p0.setMode(GPIOMode.Output)

let loop = 0
setInterval(async () => {
    // highlight-next-line
    await p0.write(loop++ % 2)
}, 1000)
```

## Input

Use `value` to read the input value of a pin. This example reads the input value every second.

```ts
import { gpio, GPIOMode } from "@devicescript/core"
import "@devicescript/gpio"

const p1 = gpio(1)
await p1.setMode(GPIOMode.Input)

// polling read pin
setInterval(async () => {
    // highlight-next-line
    const v = p1.value
    console.log({ poll: v })
}, 1000)
```

Use `subscribe` to run code whenever the pin changes state.

```ts
import { gpio, GPIOMode } from "@devicescript/core"
import "@devicescript/gpio"

const p1 = gpio(1)
await p1.setMode(GPIOMode.Input)

// highlight-next-line
p1.subscribe(v => console.log({ sub: v }))
```
